#include <stdlib.h>
 
#include <random.h>
#include <trafgen.h>
#include <ranvar.h>

class WWW_CASTELLI : public TrafficGenerator {
   FILE* outfile;        /* output trace file, enables dump */
 public:
   WWW_CASTELLI();
   virtual double next_interval(int&);
   virtual void timeout();
   int command(int argc, const char*const* argv);
 protected:
   void init();
   //double interval_;     /* average time between consecutive calls (sec) */

	double ipt_scale_;
	double ipt_shape_;
	double bpo_mean_;
	double bpo_std_;
	double opp_mean_;
	double opp_std_;
	int max_object_size;  // in bytes

   WeibullRandomVariable inter_page_time;
	LogNormalRandomVariable bytes_per_object;
	LogNormalRandomVariable objects_per_page;
};

static class WWW_CASTELLIClass : public TclClass {
 public:
   WWW_CASTELLIClass() : TclClass("Application/Traffic/WWW_CASTELLI") {}
   TclObject* create(int, const char*const*) {
   	return (new WWW_CASTELLI());
   }
} class_WWW_CASTELLI;

int WWW_CASTELLI::command(int argc, const char*const* argv){
        
   		if (argc==2) {
   			if (strcmp(argv[1], "nodump") == 0) {
   				if ( outfile ) fclose (outfile);
   				outfile = 0;
   				return (TCL_OK);
   			}
   		} else if(argc==3){
                if (strcmp(argv[1], "use-rng") == 0) {
                        inter_page_time.seed((char *)argv[2]);
                        bytes_per_object.seed((char *)argv[2]);
                        objects_per_page.seed((char *)argv[2]);
                        return (TCL_OK);
                } else if (strcmp(argv[1], "dump") == 0) {
   					 outfile = fopen (argv[2], "w");
   					 return (TCL_OK);
   				 }
        }
        return Application::command(argc,argv);
}

WWW_CASTELLI::WWW_CASTELLI() : inter_page_time (0.0, 0.0)
{
	bind_time ("ipt_scale_", &ipt_scale_);
	bind_time ("ipt_shape_", &ipt_shape_);
	bind ("bpo_mean_", &bpo_mean_);
	bind ("bpo_std_", &bpo_std_);
	bind ("opp_mean_", &opp_mean_);
	bind ("opp_std_", &opp_std_);
	bind ("max_object_size", &max_object_size);
	outfile = 0;
}

void WWW_CASTELLI::init()
{
	inter_page_time.setshape(ipt_shape_);
	inter_page_time.setscale(ipt_scale_);
	bytes_per_object.setavg(bpo_mean_);
	bytes_per_object.setstd(bpo_std_);
	objects_per_page.setavg(opp_mean_);
	objects_per_page.setstd(opp_std_);
	if (agent_)
   		if (agent_->get_pkttype() != PT_TCP && agent_->get_pkttype() != PT_TFRC)
   			agent_->set_pkttype(PT_EXP);
}

double WWW_CASTELLI::next_interval(int& size)
{

	int n_objects = int(objects_per_page.value() + .5);
	n_objects = ( n_objects >= 0 ) ? n_objects : 1;
	size = 0;

	for ( int i = 0 ; i < n_objects ; i++ ) {
		int obj_size = int ( bytes_per_object.value() + .5);
		if ( obj_size > max_object_size ) obj_size = max_object_size;
		size += obj_size;
	}

	if (size == 0) size = 1;
	double t = /* interval_ = */ inter_page_time.value();

	//fprintf (stderr, "%d %u %f\n", n_objects, size, t);

	if ( outfile ) {
		double mu = 0.0015;
		int mss = 1500;
		int npackets = size / mss;
		int i = 0;
		double time = t;
		for ( ; i < npackets ; i++ ) {
			fprintf (outfile, "%f %d\n", time * 1000.0, mss);
   		if ( i == 0 ) time = mu;
   		else time += mu;
   	}
   	fprintf (outfile, "%f %d\n", time * 1000.0, size % mss);
   }

	return(t);

}

void WWW_CASTELLI::timeout()
{
   if (! running_)
   	return;

   /* send a packet */
   // The test tcl/ex/test-rcvr.tcl relies on the "NEW_BURST" flag being 
   // set at the start of any exponential burst ("talkspurt").  
   if (nextPkttime_ == -1) 
   	agent_->sendmsg(size_, "NEW_BURST");
   else 
   	agent_->sendmsg(size_);
   /* figure out when to send the next one */
   nextPkttime_ = next_interval(size_);
   /* schedule it */
   if (nextPkttime_ > 0)
   	timer_.resched(nextPkttime_);
}
